<?php
declare(strict_types=1);

namespace App\Utils\Common\SandpayRsa {

    use App\Exception\InternalException;
    use function Hyperf\Translation\__;

    /**
     * 生成随机字符串
     * @param int $size
     * @return string
     * @throws \Exception
     */
    function generate(int $size): string
    {
        $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $data = [];
        if (function_exists('random_int')) {
            for ($i = 0; $i < $size; $i++) {
                $data[] = $str[random_int(0, strlen($str) - 1)];
            }
        } else {
            for ($i = 0; $i < $size; $i++) {
                mt_srand(crc32(uniqid(). microtime()));
                $data[] = $str[mt_rand(0, strlen($str) - 1)];
            }
        }

        return implode('', $data);
    }

    /**
     * 使用公钥加密数据
     * @param string $data
     * @param string $publicCertPath
     * @return string
     */
    function encryptByPublicKey(string $data, string $key): string
    {
        if (!openssl_public_encrypt($data, $encryptedData, $key, OPENSSL_PKCS1_PADDING)) {
            throw new InternalException(__('message.openssl.encrypt_failed'));
        }

        return base64_encode($encryptedData);
    }

    /**
     * 使用私钥解密数据
     * @param string $data
     * @param string $privateCertPath
     * @param string $pwd
     * @return string
     */
    function decryptByPrivateKey(string $data, string $pKey): string
    {
        if (!openssl_private_decrypt(
            data: base64_decode($data),
            decrypted_data: $decryptedData,
            private_key: $pKey,
            padding: OPENSSL_PKCS1_PADDING)
        ) {
            throw new InternalException(__('message.openssl.decrypt_failed'));
        }

        return (string)$decryptedData;
    }

    /**
     * 签名数据
     * @param $data
     * @param string $privateCertPath
     * @return string
     */
    function sign($data, string $privateCertPath): string
    {
        $resource = openssl_pkey_get_private($privateCertPath);
        $result = openssl_sign($data, $signature, $resource, OPENSSL_ALGO_SHA256);

        if (!$result) {
            throw new InternalException(__('message.sign.failed'));
        }

        return base64_encode($signature);
    }

    /**
     * 验证签名
     * @param $data
     * @param $signature
     * @param string $publicCertPath
     * @return bool
     */
    function verify($data, $signature, string $publicCertPath): bool
    {
        $resource = openssl_pkey_get_public($publicCertPath);
        $result = openssl_verify($data, base64_decode($signature), $resource, OPENSSL_ALGO_SHA256);
        if ($result !== 1) {
            throw new InternalException(__('message.sign.failed'));
        }

        return true;
    }

    /**
     * 加密数据
     * @param array $data
     * @param $key
     * @return string
     */
    function encrypt(array $data, string $key): string
    {
        ksort($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $cipher = 'AES-128-ECB';
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = !$ivlen ? '' : openssl_random_pseudo_bytes($ivlen);
        $result = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv);

        if (!$result) {
            throw new InternalException(__('message.openssl.encrypt_failed'));
        }
        return base64_encode($result);
    }

    /**
     * 解密数据
     * @param string $data
     * @param string $key
     * @return string
     */
    function decrypt(string $data, string $key): string
    {
        $result = openssl_decrypt(base64_decode($data), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);

        if (!$result) {
            throw new InternalException(__('message.openssl.decrypt_failed'));
        }

        return $result;
    }

    /**
     * 加载X509证书
     * @param string $publicCertPath
     * @return string
     */
    function loadX509Cert(string $publicCertPath): string
    {
        if (!$publicCertPath || !file_exists($publicCertPath)) {
            throw new InternalException(__('message.config.public_cert'));
        }
        // 读取公钥文件
        $pubKey = file_get_contents($publicCertPath);
        $cert = chunk_split(base64_encode($pubKey), 64, PHP_EOL);
        $cert = "-----BEGIN CERTIFICATE-----".PHP_EOL.$cert."-----END CERTIFICATE-----";
        $res = openssl_pkey_get_public($cert);
        $detail = openssl_pkey_get_details($res);

        if (!$detail) {
            throw new InternalException(__('message.config.public_cert'));
        }

        return $detail['key'];
    }

    /**
     * 加载PKCS12证书文件
     * @param string $privateCertPath
     * @param string $pwd
     * @return string
     */
    function loadPk12Cert(string $privateCertPath, string $pwd): string
    {
        if (!$privateCertPath || !file_exists($privateCertPath)) {
            throw new InternalException(__('message.config.private_cert'));
        }
        // 读取公钥文件
        $priKey = file_get_contents($privateCertPath);
        if (!openssl_pkcs12_read($priKey, $certs, $pwd)) {
            throw new InternalException(__('message.config.private_cert'));
        }

        return $certs['pkey'];
    }
}